﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;
using System.Reflection;
using System.Resources;
using System.Collections;
using System.Windows.Markup;
using System.IO;

namespace XAMLStylePad
{
    public class MyXamlTypeMapper : XamlTypeMapper
    {
        public MyXamlTypeMapper()
            : base(new string[] { "WindowsBase", "PresentationCore", "PresentationFramework" }, new NamespaceMapEntry[0])
        {
        }

        protected override bool AllowInternalType(Type type)
        {
            return true;
        }
    }


    internal class XAMLResourcesLoader
    {
        Assembly _assembly;

        public void LoadAssemblyByPath(string path)
        {

            FullPath = path;
            _assembly = Assembly.LoadFile(path);
        }

        public string FullPath
        {
            get;
            set;
        }

        //string[] disabledNames

        public Dictionary<string, ResourceDictionary> LoadResources()
        {
            var resources = new Dictionary<string, ResourceDictionary>();
            if(_assembly == null)
            {
                if(string.IsNullOrEmpty(FullPath))
                    return resources;

                //_assembly = Assembly.ReflectionOnlyLoadFrom(FullPath);
                _assembly = Assembly.LoadFrom(FullPath);
            }
            
            string name = _assembly.GetName().Name;
            var resNames = _assembly.GetManifestResourceNames();

            foreach(var resName in resNames)
            {
                if(!resName.EndsWith(".g.resources")) // search for *.baml stores only
                    continue;
                var resStream = _assembly.GetManifestResourceStream(resName);
                var set = new ResourceReader(resStream);

                foreach(var item in set)
                {
                    DictionaryEntry entry = (DictionaryEntry)item;
                    var part = entry.Key.ToString();
                    part = part.Substring(0, part.LastIndexOf('.')); //name of .baml resource without extension

                    var res = LoadComponent(name, part);

                    if(res != null && res is ResourceDictionary)
                    {
                        resources.Add(part, res as ResourceDictionary);
                    }
                }
            }

            return resources;
        }

        /// <summary>
        /// Try to load stored resource dictionary
        /// </summary>
        /// <param name="asmName">Assembly name</param>
        /// <param name="path">path to internal *.xaml resource without extension</param>
        /// <returns>ResourceDictionary, if it is</returns>
        //[DebuggerNonUserCode]
        object LoadComponent(string asmName, string path)
        {
            try
            {
                var uri = new Uri(string.Format(@"{0};;;component\{1}.xaml", asmName, path), UriKind.Relative);
                //var res = XamlReader.Load(Application.GetResourceStream(uri).Stream, 
                //    new ParserContext()
                //    {
                //        XamlTypeMapper = new MyXamlTypeMapper()
                //    }); 


                var stream = Application.GetResourceStream(uri);

                var res = Load(stream.Stream);
                
                //var res = Application.LoadComponent(uri);

                return res as ResourceDictionary;
                //return new ResourceDictionary()
                //{
                //    Source = new Uri(string.Format(@"{0};;;component\{1}.xaml", asmName, path), UriKind.Relative)
                //};
            }
            catch(Exception err)
            {
                Debug.WriteLine(err);
                return null;
            }
        }

        static object Load(Stream stream)
        {
            var pc = 
                //new ParserContext();
                new ParserContext()
                {
                    XamlTypeMapper = new MyXamlTypeMapper()
                };
            return typeof(XamlReader)
                .GetMethod("LoadBaml", BindingFlags.NonPublic | BindingFlags.Static)
                .Invoke(null, new object[] { stream, pc, null, false });
        }

    }
}
